#include "app_buffer.h"
#include "stdlib.h"
#include "string.h"
#include "log/log.h"

/**
 * @brief 初始化小缓冲区
 * 
 * @param size 缓冲区大小
 * @return SubBuffer* 小缓冲区指针
 */
SubBuffer *sub_buffer_init(int size)
{
    SubBuffer *sub_buffer = malloc(sizeof(SubBuffer));
    sub_buffer->ptr = malloc(size);
    sub_buffer->total_size = size;
    sub_buffer->len = 0;

    return sub_buffer;
}


/**
 * @brief 初始化缓冲区
 * 
 * @param buffer 缓冲区指针
 * @param size 缓冲区大小
 * @return Buffer* 缓冲区指针
 */
Buffer *app_buffer_init(int size)
{
    Buffer *buffer = malloc(sizeof(Buffer));
    buffer->sub_buffer[0] = sub_buffer_init(size);
    buffer->sub_buffer[1] = sub_buffer_init(size);
    buffer->read_index = 0;
    buffer->write_index = 1;

    // 初始化读锁和写锁
    pthread_mutex_init(&buffer->read_mutex, NULL);
    pthread_mutex_init(&buffer->write_mutex, NULL);

    return buffer;
}


/**
 * @brief 释放缓冲区
 * 
 * @param buffer 缓冲区指针
 */
void app_buffer_free(Buffer *buffer)
{
    free(buffer->sub_buffer[0]->ptr);
    free(buffer->sub_buffer[1]->ptr);
    free(buffer->sub_buffer[0]);
    free(buffer->sub_buffer[1]);
    free(buffer);
}


/**
 * @brief 写入数据 (一帧)
 * 
 * @param buffer 缓冲区指针
 * @param data 数据指针
 * @param len 数据长度
 * @return int 写入长度
 */
int app_buffer_write(Buffer *buffer, uint8_t *data, uint16_t len)
{
    // 检查len： 后面用一个字节存储数据长度，所以最大不能超过255
    if (len > 255)
    {
        log_debug("写入的数据长度不能超过255");
        return 0; 
    }

    // 加写锁
    log_debug("在写数据前，加写锁");
    pthread_mutex_lock(&buffer->write_mutex);

    // 得到写缓冲区
    SubBuffer *w_buffer = buffer->sub_buffer[buffer->write_index];
    // 计算剩余空间
    int rest_space = w_buffer->total_size - w_buffer->len;
    // 比较写入长度和剩余空间
    if (len + 1 > rest_space)
    {
        log_debug("写缓冲区剩余空间不足");
        // 写入长度大于剩余空间，需要切换缓冲区
        // buffer->write_index = !buffer->write_index;
        // 递归调用写入函数，写入剩余数据
        // return len - rest_space + app_buffer_write(buffer, data + rest_space, len - rest_space);
        // 解锁
        log_debug("在写数据后，解锁");
        pthread_mutex_unlock(&buffer->write_mutex);
        return 0;
    }
    // 写入数据  (先写数据长度 再写数据本身)
    w_buffer->ptr[w_buffer->len] = len;
    memcpy(w_buffer->ptr + w_buffer->len + 1, data, len);
    // 更新缓冲区长度
    w_buffer->len += len + 1;

    // 解锁
    log_debug("在写数据后，解锁");
    pthread_mutex_unlock(&buffer->write_mutex);

    // 返回写入长度
    return len;
}

/**
 * @brief 读取数据 (一帧)
 * 
 * @param buffer 缓冲区指针
 * @param data 数据指针
 * @param len 数据长度
 * @return int 读取长度
 */
int app_buffer_read(Buffer *buffer, uint8_t *data, uint16_t len)
{
    // 加读锁
    log_debug("在读数据前，加读锁");
    pthread_mutex_lock(&buffer->read_mutex);

    // 得到缓冲区
    SubBuffer *r_buffer = buffer->sub_buffer[buffer->read_index];
    // 如果读缓冲区为空，切换读写缓冲区  如果还是空的，返回-1
    if (r_buffer->len == 0)
    {
        // 在准备切换前，加写锁 
        log_debug("在准备切换前，加写锁");
        pthread_mutex_lock(&buffer->write_mutex);
        int temp = buffer->read_index;
        buffer->read_index = buffer->write_index;
        buffer->write_index = temp;
        r_buffer = buffer->sub_buffer[buffer->read_index];
        // 解锁
        log_debug("在切换读写缓冲区后，解锁");
        pthread_mutex_unlock(&buffer->write_mutex);
        if (r_buffer->len == 0)
        {
            log_debug("读缓冲区为空, 切换读写缓冲区后，还是为空");
            // 解锁
            log_debug("在读数据后，解锁");
            pthread_mutex_unlock(&buffer->read_mutex);
            return -1;
        }
    }


    // 从中读取第一帧数据（数据长度+数据本身），并保存到data， 并将剩余的数据移动最左边
    int data_len = r_buffer->ptr[0];
    // 检查data空间是否足够
    if (data_len > len)
    {
        log_debug("读取数据长度大于data空间长度");
        // 解锁
        log_debug("在读数据后，解锁");
        pthread_mutex_unlock(&buffer->read_mutex);
        return -1;
    }

    memcpy(data, r_buffer->ptr + 1, len);
    memmove(r_buffer->ptr, r_buffer->ptr + len + 1, r_buffer->len - len - 1);
    r_buffer->len -= len + 1;
    

    // 解锁
    log_debug("在读数据后，解锁");
    pthread_mutex_unlock(&buffer->read_mutex);

    return len;
}